<template>
  <!-- 主表 -->
  <div class="table-layout">
    <slot name="actionBefore"/>
    <TableToolWidget class="action-layout" v-if="!props.hideHeader"
                     :columns="columns" :actions="props.toolActions"
                     :refresh-trigger="onRefresh" :column-trigger="onShowColumn"
                     :zebra-trigger="onZebra" :show-zebra="props.isShowZebra"
                     :show-refresh="props.showRefresh" :show-column="props.showColumn">
      <template v-slot:header>
        <slot name="toolHeader"/>
      </template>
      <template v-slot:before>
        <slot name="toolBefore"/>
      </template>
    </TableToolWidget>
    <slot name="actionAfter"/>
    <div ref="$tableRef" class="table-container">
      <el-table
          ref="refTable"
          :header-cell-style="{ background: '#FAFAFA', color: '#000', fontWeight: 'bold' }"
          :stripe="showZebra"
          :data="data"
          :border="tableBorder"
          sortable="custom"
          row-key="id"
          :max-height="tableHeight"
          default-expand-all
          v-loading="loading"
          @sort-change="sortChangeHandle"
          @selection-change="selectionChangeHandle">
        <el-table-column v-if="hasSelect" type="selection" header-align="center" align="center" width="50"/>

        <template v-for="(item) in columns" :key="item.id">
          <el-table-column :prop="item.id" header-align="center" align="center"
                           :label="item.name" :column-key="item.id" :key="item.id"
                           :sortable="item.sort" v-if="item.show"
                           :width="item.width" :fixed="item.fixed"
                           :show-overflow-tooltip="true"
                           :filter-method="item.filterMethod ? item.filterMethod : undefined">
            <template #default="scope">
              <template v-if="item.operations && item.operations.length > 0">
                <template v-for="(op) in item.operations" :key="op.name">
                  <template v-if="op.type === 'confirm'">
                    <el-popconfirm
                        confirm-button-text="确定"
                        cancel-button-text="取消"
                        :icon="InfoFilled"
                        icon-color="#626AEF"
                        :disabled="op.disabled && op.disabled(toRaw(scope.row))"
                        :title="op.tips ? op.tips(toRaw(scope.row)) : '确定删除？'"
                        @confirm="() => op.confirm ? op.confirm(data, toRaw(scope.row), scope.$index) : {}"
                        @cancel="() => op.cancel ? op.cancel(data, toRaw(scope.row), scope.$index) : {}">
                      <template #reference>
                        <el-button link :type="op.iconType ? op.iconType : 'danger'" size="small"
                                   :disabled="op.disabled && op.disabled(toRaw(scope.row))">
                          {{ op.render ? op.render(toRaw(scope.row)) : op.name }}
                        </el-button>
                      </template>
                    </el-popconfirm>
                  </template>
                  <template v-else>
                    <el-button link :type="op.iconType ? op.iconType : 'primary'" size="small"
                               :disabled="op.disabled && op.disabled(scope.row)"
                               @click="() => op.callback(data, toRaw(scope.row), scope.$index, item, columns)">
                      {{ op.render ? op.render(toRaw(scope.row)) : op.name }}
                    </el-button>
                  </template>
                </template>
              </template>
              <template v-else-if="item.tag ==='true'">
                <el-tag v-if="item.tagType" :type="item.tagType(scope.row[item.id])" disable-transitions>
                  {{ item.tagText(scope.row[item.id]) }}
                </el-tag>
                <div v-if="!item.tagType && !item.tagStyle">
                  {{ item.tagText(scope.row[item.id]) }}
                </div>
                <div v-if="!item.tagType && item.tagStyle" :style="[item.tagStyle(scope.row[item.id])]">
                  {{ item.tagText(scope.row[item.id]) }}
                </div>
              </template>
              <template v-else-if="item.action">
                <el-button link :type="item.iconType ? item.iconType : 'primary'" size="small"
                           :disabled="item.disabled && item.disabled(scope.row)"
                           @click="() => item.action(data, toRaw(scope.row), scope.$index, item)">
                  {{ scope.row[item.id] || '--' }}
                </el-button>
              </template>
              <template v-else>
                {{ scope.row[item.id] || '--' }}
              </template>
            </template>
          </el-table-column>
        </template>
        <template #empty>
          <el-empty v-show="hasLoad" description="暂无数据"/>
        </template>
      </el-table>
      <el-pagination
          class="wg-table-pagination hi-table-bot"
          v-if="!hidePageable"
          :style="[getWrapPaginationStyle()]"
          :current-page="pagination.current || 1"
          :page-sizes="pagination.sizes || [10, 20, 50, 100]"
          :default-page-size="pagination.pageSize || 10"
          :total="pagination.total || 0"
          layout="->, total, sizes, prev, pager, next, jumper"
          @size-change="sizeChangeHandle"
          @current-change="currentChangeHandle"/>
    </div>

    <slot name="bottom"/>
  </div>
</template>

<script setup lang="ts">

import {nextTick, onMounted, onUnmounted, ref, toRaw} from "vue";
import {InfoFilled} from "@element-plus/icons-vue";
import TableToolWidget from "@/widget/TableToolWidget.vue";
import {runMethod} from "@/utils/DateUtil";

const tableHeight = ref(200);
const refTable = ref();
const $tableRef = ref(null);

const hasLoad = ref(false);
const data = ref<Record<string, any>[]>();
const loading = ref(false);
const searchParams = ref({});
const showZebra = ref(false);

const props = withDefaults(defineProps<{
  load?: any,
  canPage?: boolean,
  columns: any,
  toolActions?: any,
  hasSelect: boolean,
  hidePageable: boolean,
  pagination: any,
  showBorder?: boolean;
  tableBorder?: boolean;
  tableToolRound?: string | undefined;
  tableToolBackground?: string | undefined;
  tableMargin?: string | undefined;
  isShowZebra?: boolean,
  showColumn?: boolean,
  showRefresh?: boolean,
  selected?: any,
  hideHeader?: boolean,
}>(), {
  hasSelect: false,
  hidePageable: false,
  isShowZebra: true,
  showColumn: true,
  showRefresh: true,
  columns: [],
  pagination: () => {
    return {
      current: 1,
      pageSize: 10,
      total: 0,
      sizes: [10, 20, 50, 100],
    }
  }
});

const paginationHei: number = 68;
const initSelItems = ref(props.selected || []);
const selectItems = ref([]);
const columns = props.columns;
const pagination = ref(props.pagination);
const tableBorder = ref(props.tableBorder);
const showBorder = ref(tableBorder.value ? true : props.showBorder);
let observer: ResizeObserver | null = null;
let refTimer = ref();

const handleResize = (entries: any) => {
  if (refTimer.value) {
    clearTimeout(refTimer.value);
  }
  for (const entry of entries) {
    const {height} = entry.contentRect;
    const hei: number = height - (props.hidePageable ? 0 : paginationHei);
    if (tableHeight.value !== hei) {
      tableHeight.value = hei;
    }
  }
}

onMounted(() => {
  if ($tableRef.value) {
    observer = new ResizeObserver(handleResize);
    observer.observe($tableRef.value);
  }
})

onUnmounted(() => {
  if (observer) {
    observer.disconnect();
  }
});

const getWrapPaginationStyle = () => {
  return {
    "border-left": showBorder.value ? '1px solid #ebeef5' : '',
    "border-bottom": showBorder.value ? '1px solid #ebeef5' : '',
    "border-right": showBorder.value ? '1px solid #ebeef5' : '',
    "border-bottom-left-radius": props.tableToolRound || '0',
    "border-bottom-right-radius": props.tableToolRound || '0',
  }
}

const updateSelection = () => {
  const ret: any = toRaw(initSelItems.value);
  refTable.value?.clearSelection();
  if (ret && data) {
    ret.forEach((row: any) => {
      refTable.value?.toggleRowSelection(row, true)
    })
  }
}

const sortChangeHandle = () => {

}

const selectionChangeHandle = (val: any) => {
  selectItems.value = val;
}

const sizeChangeHandle = (size: any) => {
  pagination.value.pageSize = size;
  loadData({});
}

const currentChangeHandle = (pageNo: any) => {
  pagination.value.current = pageNo;
  loadData({});
}

const onShowColumn = (item: any) => {
  columns.forEach((col: any) => {
    if (col.id === item.id) {
      col.show = item.show;
    }
  })
}

const onZebra = (isShow: boolean) => {
  showZebra.value = isShow;
}

/**
 * 刷新表格内容
 */
const onRefresh = () => {
  loadData({});
}

const doLoadData = async () => {
  const params = searchParams.value;
  if (props.load) {
    return await props.load({
      current: pagination.value?.current,
      pageSize: pagination.value?.pageSize,
      ...params
    });
  }
}

const loadData = async (params: any) => {
  loading.value = true;
  hasLoad.value = false;

  const result = await runMethod(params, doLoadData);
  if (!result || result.code != 0 || !result.data || !result.data.data) {
    data.value = [];
    pagination.value.total = 0;
  } else if (result.code === 0) {
    data.value = toRaw(result.data.data);
    pagination.value.total = result.data.total || 0;

    if (pagination.value.total === 0 && data.value) {
      pagination.value.total = data.value.length;
    }
    if (initSelItems.value) {
      await nextTick(() => updateSelection());
    }
  }
  hasLoad.value = data.value?.length === 0;
  loading.value = false;
}

const refreshData = async (params: any) => {
  searchParams.value = params || {};
  return await loadData(params);
}

const restoreData = (resData: any) => {
  data.value = resData.data;
  showZebra.value = resData.isZebra;
  pagination.value = resData.pagination;
  searchParams.value = resData.params;
}

const getRestoreData = () => {
  return {
    isZebra: showZebra.value,
    data: data.value,
    pagination: pagination.value,
    params: searchParams.value,
  }
}

const getSelectItems = () => {
  return selectItems.value;
}

const setSelectItems = (items: any) => {
  initSelItems.value = toRaw(items);
}

defineExpose({
  refreshData,
  restoreData,
  getRestoreData,
  getSelectItems,
  setSelectItems,
  updateSelection,
});

</script>

<style scoped>
.table-layout {
  display: flex;
  flex: 1;
  flex-direction: column;
  overflow: hidden !important;
}

.action-layout {
  display: flex;
  flex-direction: row;
}

.table-container {
  width: 100%;
  flex: 1;
  padding: 0 0;
  background: #fff;
  overflow: hidden !important;
}

.hi-table-bot {
  height: 60px;
  text-align: center;
  padding: 4px 0;
  margin-top: 8px;
}

.wg-table-pagination {
  padding: 16px 32px;
  background: #fff;
}

</style>
